home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / LANG / C / GCC / V2-4-5 / GPPLIBSR00 / cc / sbufvscan < prev    next >
Text File  |  1993-12-08  |  31KB  |  756 lines

  1. /*
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. // Extensively hacked for GNU iostream by Per Bothner 1991, 1992.
  19. // Changes copyright Per Bothner 1992.
  20.  
  21. #if defined(LIBC_SCCS) && !defined(lint)
  22. static char sccsid[] = "%W% (Berkeley) %G%";
  23. #endif /* LIBC_SCCS and not lint */
  24.  
  25. #include "ioprivate.h"
  26.  
  27. extern "C"
  28.   {
  29.   #include <ctype.h>
  30.   #ifndef NO_STDARG
  31.   #include <stdarg.h>
  32.   #else
  33.   #include <varargs.h>
  34.   #endif
  35.   }
  36.  
  37.  
  38. #ifndef NO_FLOATING_POINT
  39. #define FLOATING_POINT
  40. #endif
  41.  
  42. #ifdef FLOATING_POINT
  43. #include "floatio.h"
  44. #define BUF     (MAXEXP+MAXFRACT+3)     /* 3 = sign + decimal point + NUL */
  45. #else
  46. #define BUF     40
  47. #endif
  48.  
  49. /*
  50.  * Flags used during conversion.
  51.  */
  52. #define LONG            0x01    /* l: long or double */
  53. #define LONGDBL         0x02    /* L: long double; unimplemented */
  54. #define SHORT           0x04    /* h: short */
  55. #define SUPPRESS        0x08    /* suppress assignment */
  56. #define POINTER         0x10    /* weird %p pointer (`fake hex') */
  57. #define NOSKIP          0x20    /* do not skip blanks */
  58.  
  59. /*
  60.  * The following are used in numeric conversions only:
  61.  * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
  62.  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
  63.  */
  64. #define SIGNOK          0x40    /* +/- is (still) legal */
  65. #define NDIGITS         0x80    /* no digits detected */
  66.  
  67. #define DPTOK           0x100   /* (float) decimal point is still legal */
  68. #define EXPOK           0x200   /* (float) exponent (e+3, etc) still legal */
  69.  
  70. #define PFXOK           0x100   /* 0x prefix is (still) legal */
  71. #define NZDIGITS        0x200   /* no zero digits detected */
  72.  
  73. /*
  74.  * Conversion types.
  75.  */
  76. #define CT_CHAR         0       /* %c conversion */
  77. #define CT_CCL          1       /* %[...] conversion */
  78. #define CT_STRING       2       /* %s conversion */
  79. #define CT_INT          3       /* integer, i.e., strtol or strtoul */
  80. #define CT_FLOAT        4       /* floating, i.e., strtod */
  81.  
  82. #define u_char unsigned char
  83. #define u_long unsigned long
  84.  
  85. //extern "C" u_long strtoul(const char*, char**, int);
  86. static const u_char *__sccl(register char *tab, register const u_char *fmt);
  87.  
  88. // If state is non-NULL, set failbit and/or eofbit as appropriate.
  89.  
  90. int streambuf::vscan(char const *fmt0,
  91.                      _G_va_list ap,
  92.                      ios *stream /* = NULL */)
  93. {
  94.         register const u_char *fmt = (const u_char *)fmt0;
  95.         register int c;         /* character from format, or conversion */
  96.         register size_t width;  /* field width, or 0 */
  97.         register char *p;       /* points into all kinds of strings */
  98.         register int n;         /* handy integer */
  99.         register int flags;     /* flags as defined above */
  100.         register char *p0;      /* saves original value of p when necessary */
  101.         int nassigned;          /* number of fields assigned */
  102.         int nread;              /* number of characters consumed from fp */
  103.         // Assignments to base and ccfn are just to suppress warnings from gcc.
  104.         int base = 0;           /* base argument to strtol/strtoul */
  105.         u_long (*ccfn)(const char*, char**, int) = 0;
  106.         // conversion function (strtol/strtoul)
  107.         char ccltab[256];       /* character class table for %[...] */
  108.         char buf[BUF];          /* buffer for numeric conversions */
  109.         int seen_eof = 0;
  110.  
  111.         /* `basefix' is used to avoid `if' tests in the integer scanner */
  112.         static short basefix[17] =
  113.                 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
  114.  
  115.         nassigned = 0;
  116.         nread = 0;
  117.         for (;;) {
  118.                 c = *fmt++;
  119.                 if (c == 0)
  120.                         goto done;
  121.                 if (isspace(c)) {
  122.                         for (;;) {
  123.                                 c = sbumpc();
  124.                                 if (c == EOF)
  125.                                     goto eof_failure;
  126.                                 if (!isspace(c)) {
  127.                                     sputbackc(c);
  128.                                     break;
  129.                                 }
  130.                                 nread++;
  131.                         }
  132.                         continue;
  133.                 }
  134.                 if (c != '%')
  135.                         goto literal;
  136.                 width = 0;
  137.                 flags = 0;
  138.                 /*
  139.                  * switch on the format.  continue if done;
  140.                  * break once format type is derived.
  141.                  */
  142. again:          c = *fmt++;
  143.                 switch (c) {
  144.                 case '%':
  145. literal:
  146.                         n = sbumpc();
  147.                         if (n == EOF)
  148.                             goto eof_failure;
  149.                         if (n != c) {
  150.                             sputbackc(n);
  151.                             goto match_failure;
  152.                         }
  153.                         nread++;
  154.                         continue;
  155.  
  156.                 case '*':
  157.                         flags |= SUPPRESS;
  158.                         goto again;
  159.                 case 'l':
  160.                         flags |= LONG;
  161.                         goto again;
  162.                 case 'L':
  163.                         flags |= LONGDBL;
  164.                         goto again;
  165.                 case 'h':
  166.                         flags |= SHORT;
  167.                         goto again;
  168.  
  169.                 case '0': case '1': case '2': case '3': case '4':
  170.                 case '5': case '6': case '7': case '8': case '9':
  171.                         width = width * 10 + c - '0';
  172.                         goto again;
  173.  
  174.                 /*
  175.                  * Conversions.
  176.                  * Those marked `compat' are for 4.[123]BSD compatibility.
  177.                  *
  178.                  * (According to ANSI, E and X formats are supposed
  179.                  * to the same as e and x.  Sorry about that.)
  180.                  */
  181.                 case 'D':       /* compat */
  182.                         flags |= LONG;
  183.                         /* FALLTHROUGH */
  184.                 case 'd':
  185.                         c = CT_INT;
  186.                         ccfn = (u_long (*)(const char, char**, int))strtol;
  187.                         base = 10;
  188.                         break;
  189.  
  190.                 case 'i':
  191.                         c = CT_INT;
  192.                         ccfn = (u_long (*)(const char, char**, int))strtol;
  193.                         base = 0;
  194.                         break;
  195.  
  196.                 case 'O':       /* compat */
  197.                         flags |= LONG;
  198.                         /* FALLTHROUGH */
  199.                 case 'o':
  200.                         c = CT_INT;
  201.                         ccfn = strtoul;
  202.                         base = 8;
  203.                         break;
  204.  
  205.                 case 'u':
  206.                         c = CT_INT;
  207.                         ccfn = strtoul;
  208.                         base = 10;
  209.                         break;
  210.  
  211.                 case 'X':       /* compat   XXX */
  212.                         flags |= LONG;
  213.                         /* FALLTHROUGH */
  214.                 case 'x':
  215.                         flags |= PFXOK; /* enable 0x prefixing */
  216.                         c = CT_INT;
  217.                         ccfn = strtoul;
  218.                         base = 16;
  219.                         break;
  220.  
  221. #ifdef FLOATING_POINT
  222.                 case 'E':       /* compat   XXX */
  223.                 case 'F':       /* compat */
  224.                         flags |= LONG;
  225.                         /* FALLTHROUGH */
  226.                 case 'e': case 'f': case 'g':
  227.                         c = CT_FLOAT;
  228.                         break;
  229. #endif
  230.  
  231.                 case 's':
  232.                         c = CT_STRING;
  233.                         break;
  234.  
  235.                 case '[':
  236.                         fmt = __sccl(ccltab, fmt);
  237.                         flags |= NOSKIP;
  238.                         c = CT_CCL;
  239.                         break;
  240.  
  241.                 case 'c':
  242.                         flags |= NOSKIP;
  243.                         c = CT_CHAR;
  244.                         break;
  245.  
  246.                 case 'p':       /* pointer format is like hex */
  247.                         flags |= POINTER | PFXOK;
  248.                         c = CT_INT;
  249.                         ccfn = strtoul;
  250.                         base = 16;
  251.                         break;
  252.  
  253.                 case 'n':
  254.                         if (flags & SUPPRESS)   /* ??? */
  255.                                 continue;
  256.                         if (flags & SHORT)
  257.                                 *va_arg(ap, short *) = nread;
  258.                         else if (flags & LONG)
  259.                                 *va_arg(ap, long *) = nread;
  260.                         else
  261.                                 *va_arg(ap, int *) = nread;
  262.                         continue;
  263.  
  264.                 /*
  265.                  * Disgusting backwards compatibility hacks.    XXX
  266.                  */
  267.                 case '\0':      /* compat */
  268.                         nassigned = EOF;
  269.                         goto done;
  270.  
  271.                 default:        /* compat */
  272.                         if (isupper(c))
  273.                                 flags |= LONG;
  274.                         c = CT_INT;
  275.                         ccfn = (u_long (*)(const char, char**, int))strtol;
  276.                         base = 10;
  277.                         break;
  278.                 }
  279.  
  280.                 /*
  281.                  * We have a conversion that requires input.
  282.                  */
  283.                 if (sgetc() == EOF)
  284.                         goto eof_failure;
  285.  
  286.                 /*
  287.                  * Consume leading white space, except for formats
  288.                  * that suppress this.
  289.                  */
  290.                 if ((flags & NOSKIP) == 0) {
  291.                     n = *_gptr;
  292.                     while (isspace(n)) {
  293.                         _gptr++;
  294.                         nread++;
  295.                         n = sgetc();
  296.                         if (n == EOF)
  297.                             goto eof_failure;
  298.                     }
  299.                     // Note that there is at least one character in
  300.                     // the buffer, so conversions that do not set NOSKIP
  301.                     // can no longer result in an input failure.
  302.                 }
  303.  
  304.                 /*
  305.                  * Do the conversion.
  306.                  */
  307.                 switch (c) {
  308.  
  309.                 case CT_CHAR:
  310.                         /* scan arbitrary characters (sets NOSKIP) */
  311.                         if (width == 0) // FIXME!
  312.                                 width = 1;
  313.                         if (flags & SUPPRESS) {
  314.                             size_t sum = 0;
  315.                             for (;;) {
  316.                                 if ((n = _egptr - _gptr) < (int)width) {
  317.                                     sum += n;
  318.                                     width -= n;
  319.                                     _gptr += n;
  320.                                     if (underflow() == EOF)
  321.                                         if (sum == 0)
  322.                                             goto eof_failure;
  323.                                         else {
  324.                                             seen_eof++;
  325.                                             break;
  326.                                         }
  327.                                 } else {
  328.                                     sum += width;
  329.                                     _gptr += width;
  330.                                     break;
  331.                                 }
  332.                             }
  333.                             nread += sum;
  334.                         } else {
  335.                             size_t r = sgetn((char*)va_arg(ap, char*),
  336.                                                  width);
  337.                             if (r != width)
  338.                                 goto eof_failure;
  339.                             nread += r;
  340.                             nassigned++;
  341.                         }
  342.                         break;
  343.  
  344.                 case CT_CCL:
  345.                         /* scan a (nonempty) character class (sets NOSKIP) */
  346.                         if (width == 0)
  347.                                 width = ~0;     /* `infinity' */
  348.                         /* take only those things in the class */
  349.                         if (flags & SUPPRESS) {
  350.                                 n = 0;
  351.                                 while (ccltab[*_gptr]) {
  352.                                     n++, _gptr++;
  353.                                     if (--width == 0)
  354.                                         break;
  355.                                     if (sgetc() == EOF) {
  356.                                         if (n == 0)
  357.                                             goto eof_failure;
  358.                                         seen_eof++;
  359.                                         break;
  360.                                     }
  361.                                 }
  362.                                 if (n == 0)
  363.                                         goto match_failure;
  364.                         } else {
  365.                             p0 = p = va_arg(ap, char *);
  366.                             while (ccltab[*_gptr]) {
  367.                                 *p++ = *_gptr++;
  368.                                 if (--width == 0)
  369.                                     break;
  370.                                 if (sgetc() == EOF) {
  371.                                     if (p == p0)
  372.                                         goto eof_failure;
  373.                                     seen_eof++;
  374.                                     break;
  375.                                 }
  376.                             }
  377.                             n = p - p0;
  378.                             if (n == 0)
  379.                                 goto match_failure;
  380.                             *p = 0;
  381.                             nassigned++;
  382.                         }
  383.                         nread += n;
  384.                         break;
  385.  
  386.                 case CT_STRING:
  387.                         /* like CCL, but zero-length string OK, & no NOSKIP */
  388.                         if (width == 0)
  389.                                 width = ~0;
  390.                         if (flags & SUPPRESS) {
  391.                                 n = 0;
  392.                                 while (!isspace(*_gptr)) {
  393.                                         n++, _gptr++;
  394.                                         if (--width == 0)
  395.                                                 break;
  396.                                         if (sgetc() == EOF) {
  397.                                             seen_eof++;
  398.                                             break;
  399.                                         }
  400.                                 }
  401.                                 nread += n;
  402.                         } else {
  403.                                 p0 = p = va_arg(ap, char *);
  404.                                 while (!isspace(*_gptr)) {
  405.                                         *p++ = *_gptr++;
  406.                                         if (--width == 0)
  407.                                                 break;
  408.                                         if (sgetc() == EOF) {
  409.                                             seen_eof++;
  410.                                             break;
  411.                                         }
  412.                                 }
  413.                                 *p = 0;
  414.                                 nread += p - p0;
  415.                                 nassigned++;
  416.                         }
  417.                         continue;
  418.  
  419.                 case CT_INT:
  420.                         /* scan an integer as if by strtol/strtoul */
  421.                         if (width == 0 || width > sizeof(buf) - 1)
  422.                                 width = sizeof(buf) - 1;
  423.                         flags |= SIGNOK | NDIGITS | NZDIGITS;
  424.                         for (p = buf; width; width--) {
  425.                                 c = *_gptr;
  426.                                 /*
  427.                                  * Switch on the character; `goto ok'
  428.                                  * if we accept it as a part of number.
  429.                                  */
  430.                                 switch (c) {
  431.  
  432.                                 /*
  433.                                  * The digit 0 is always legal, but is
  434.                                  * special.  For %i conversions, if no
  435.                                  * digits (zero or nonzero) have been
  436.                                  * scanned (only signs), we will have
  437.                                  * base==0.  In that case, we should set
  438.                                  * it to 8 and enable 0x prefixing.
  439.                                  * Also, if we have not scanned zero digits
  440.                                  * before this, do not turn off prefixing
  441.                                  * (someone else will turn it off if we
  442.                                  * have scanned any nonzero digits).
  443.                                  */
  444.                                 case '0':
  445.                                         if (base == 0) {
  446.                                                 base = 8;
  447.                                                 flags |= PFXOK;
  448.                                         }
  449.                                         if (flags & NZDIGITS)
  450.                                             flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
  451.                                         else
  452.                                             flags &= ~(SIGNOK|PFXOK|NDIGITS);
  453.                                         goto ok;
  454.  
  455.                                 /* 1 through 7 always legal */
  456.                                 case '1': case '2': case '3':
  457.                                 case '4': case '5': case '6': case '7':
  458.                                         base = basefix[base];
  459.                                         flags &= ~(SIGNOK | PFXOK | NDIGITS);
  460.                                         goto ok;
  461.  
  462.                                 /* digits 8 and 9 ok iff decimal or hex */
  463.                                 case '8': case '9':
  464.                                         base = basefix[base];
  465.                                         if (base <= 8)
  466.                                                 break;  /* not legal here */
  467.                                         flags &= ~(SIGNOK | PFXOK | NDIGITS);
  468.                                         goto ok;
  469.  
  470.                                 /* letters ok iff hex */
  471.                                 case 'A': case 'B': case 'C':
  472.                                 case 'D': case 'E': case 'F':
  473.                                 case 'a': case 'b': case 'c':
  474.                                 case 'd': case 'e': case 'f':
  475.                                         /* no need to fix base here */
  476.                                         if (base <= 10)
  477.                                                 break;  /* not legal here */
  478.                                         flags &= ~(SIGNOK | PFXOK | NDIGITS);
  479.                                         goto ok;
  480.  
  481.                                 /* sign ok only as first character */
  482.                                 case '+': case '-':
  483.                                         if (flags & SIGNOK) {
  484.                                                 flags &= ~SIGNOK;
  485.                                                 goto ok;
  486.                                         }
  487.                                         break;
  488.  
  489.                                 /* x ok iff flag still set & 2nd char */
  490.                                 case 'x': case 'X':
  491.                                         if (flags & PFXOK && p == buf + 1) {
  492.                                                 base = 16;      /* if %i */
  493.                                                 flags &= ~PFXOK;
  494.                                                 goto ok;
  495.                                         }
  496.                                         break;
  497.                                 }
  498.  
  499.                                 /*
  500.                                  * If we got here, c is not a legal character
  501.                                  * for a number.  Stop accumulating digits.
  502.                                  */
  503.                                 break;
  504.                 ok:
  505.                                 /*
  506.                                  * c is legal: store it and look at the next.
  507.                                  */
  508.                                 *p++ = c;
  509.                                 _gptr++;
  510.                                 if (sgetc() == EOF) {
  511.                                     seen_eof++;
  512.                                     break;              /* EOF */
  513.                                 }
  514.                         }
  515.                         /*
  516.                          * If we had only a sign, it is no good; push
  517.                          * back the sign.  If the number ends in `x',
  518.                          * it was [sign] '0' 'x', so push back the x
  519.                          * and treat it as [sign] '0'.
  520.                          */
  521.                         if (flags & NDIGITS) {
  522.                                 if (p > buf)
  523.                                         (void) sputbackc(*(u_char *)--p);
  524.                                 goto match_failure;
  525.                         }
  526.                         c = ((u_char *)p)[-1];
  527.                         if (c == 'x' || c == 'X') {
  528.                                 --p;
  529.                                 (void) sputbackc(c);
  530.                         }
  531.                         if ((flags & SUPPRESS) == 0) {
  532.                                 u_long res;
  533.  
  534.                                 *p = 0;
  535.                                 res = (*ccfn)(buf, (char **)NULL, base);
  536.                                 if (flags & POINTER)
  537.                                         *va_arg(ap, void **) = (void *)res;
  538.                                 else if (flags & SHORT)
  539.                                         *va_arg(ap, short *) = res;
  540.                                 else if (flags & LONG)
  541.                                         *va_arg(ap, long *) = res;
  542.                                 else
  543.                                         *va_arg(ap, int *) = res;
  544.                                 nassigned++;
  545.                         }
  546.                         nread += p - buf;
  547.                         break;
  548.  
  549. #ifdef FLOATING_POINT
  550.                 case CT_FLOAT:
  551.                         /* scan a floating point number as if by strtod */
  552.                         if (width == 0 || width > sizeof(buf) - 1)
  553.                                 width = sizeof(buf) - 1;
  554.                         flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
  555.                         for (p = buf; width; width--) {
  556.                                 c = *_gptr;
  557.                                 /*
  558.                                  * This code mimicks the integer conversion
  559.                                  * code, but is much simpler.
  560.                                  */
  561.                                 switch (c) {
  562.  
  563.                                 case '0': case '1': case '2': case '3':
  564.                                 case '4': case '5': case '6': case '7':
  565.                                 case '8': case '9':
  566.                                         flags &= ~(SIGNOK | NDIGITS);
  567.                                         goto fok;
  568.  
  569.                                 case '+': case '-':
  570.                                         if (flags & SIGNOK) {
  571.                                                 flags &= ~SIGNOK;
  572.                                                 goto fok;
  573.                                         }
  574.                                         break;
  575.                                 case '.':
  576.                                         if (flags & DPTOK) {
  577.                                                 flags &= ~(SIGNOK | DPTOK);
  578.                                                 goto fok;
  579.                                         }
  580.                                         break;
  581.                                 case 'e': case 'E':
  582.                                         /* no exponent without some digits */
  583.                                         if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
  584.                                                 flags =
  585.                                                     (flags & ~(EXPOK|DPTOK)) |
  586.                                                     SIGNOK | NDIGITS;
  587.                                                 goto fok;
  588.                                         }
  589.                                         break;
  590.                                 }
  591.                                 break;
  592.                 fok:
  593.                                 *p++ = c;
  594.                                 _gptr++;
  595.                                 if (sgetc() == EOF) {
  596.                                     seen_eof++;
  597.                                     break;      /* EOF */
  598.                                 }
  599.                         }
  600.                         /*
  601.                          * If no digits, might be missing exponent digits
  602.                          * (just give back the exponent) or might be missing
  603.                          * regular digits, but had sign and/or decimal point.
  604.                          */
  605.                         if (flags & NDIGITS) {
  606.                                 if (flags & EXPOK) {
  607.                                         /* no digits at all */
  608.                                         while (p > buf)
  609.                                             sputbackc(*(u_char *)--p);
  610.                                         goto match_failure;
  611.                                 }
  612.                                 /* just a bad exponent (e and maybe sign) */
  613.                                 c = *(u_char *)--p;
  614.                                 if (c != 'e' && c != 'E') {
  615.                                         (void)sputbackc(c);/* sign */
  616.                                         c = *(u_char *)--p;
  617.                                 }
  618.                                 (void) sputbackc(c);
  619.                         }
  620.                         if ((flags & SUPPRESS) == 0) {
  621.                                 double res;
  622.                                 *p = 0;
  623. #ifdef USE_DTOA
  624.                                 res = strtod(buf, NULL);
  625. #else
  626.                                 res = atof(buf);
  627. #endif
  628.                                 if (flags & LONG)
  629.                                         *va_arg(ap, double *) = res;
  630.                                 else
  631.                                         *va_arg(ap, float *) = res;
  632.                                 nassigned++;
  633.                         }
  634.                         nread += p - buf;
  635.                         break;
  636. #endif /* FLOATING_POINT */
  637.                 }
  638.         }
  639. eof_failure:
  640.         seen_eof++;
  641. input_failure:
  642.         if (nassigned == 0)
  643.             nassigned = -1;
  644. match_failure:
  645.         if (stream)
  646.             stream->set(ios::failbit);
  647. done:
  648.         if (stream && seen_eof)
  649.                 stream->set(ios::eofbit);
  650.         return (nassigned);
  651. }
  652.  
  653. /*
  654.  * Fill in the given table from the scanset at the given format
  655.  * (just after `[').  Return a pointer to the character past the
  656.  * closing `]'.  The table has a 1 wherever characters should be
  657.  * considered part of the scanset.
  658.  */
  659. static const u_char *__sccl(register char *tab, register const u_char *fmt)
  660. {
  661.         register int c, n, v;
  662.  
  663.         /* first `clear' the whole table */
  664.         c = *fmt++;             /* first char hat => negated scanset */
  665.         if (c == '^') {
  666.                 v = 1;          /* default => accept */
  667.                 c = *fmt++;     /* get new first char */
  668.         } else
  669.                 v = 0;          /* default => reject */
  670.         /* should probably use memset here */
  671.         for (n = 0; n < 256; n++)
  672.                 tab[n] = v;
  673.         if (c == 0)
  674.                 return (fmt - 1);/* format ended before closing ] */
  675.  
  676.         /*
  677.          * Now set the entries corresponding to the actual scanset
  678.          * to the opposite of the above.
  679.          *
  680.          * The first character may be ']' (or '-') without being special;
  681.          * the last character may be '-'.
  682.          */
  683.         v = 1 - v;
  684.         for (;;) {
  685.                 tab[c] = v;             /* take character c */
  686. doswitch:
  687.                 n = *fmt++;             /* and examine the next */
  688.                 switch (n) {
  689.  
  690.                 case 0:                 /* format ended too soon */
  691.                         return (fmt - 1);
  692.  
  693.                 case '-':
  694.                         /*
  695.                          * A scanset of the form
  696.                          *      [01+-]
  697.                          * is defined as `the digit 0, the digit 1,
  698.                          * the character +, the character -', but
  699.                          * the effect of a scanset such as
  700.                          *      [a-zA-Z0-9]
  701.                          * is implementation defined.  The V7 Unix
  702.                          * scanf treats `a-z' as `the letters a through
  703.                          * z', but treats `a-a' as `the letter a, the
  704.                          * character -, and the letter a'.
  705.                          *
  706.                          * For compatibility, the `-' is not considerd
  707.                          * to define a range if the character following
  708.                          * it is either a close bracket (required by ANSI)
  709.                          * or is not numerically greater than the character
  710.                          * we just stored in the table (c).
  711.                          */
  712.                         n = *fmt;
  713.                         if (n == ']' || n < c) {
  714.                                 c = '-';
  715.                                 break;  /* resume the for(;;) */
  716.                         }
  717.                         fmt++;
  718.                         do {            /* fill in the range */
  719.                                 tab[++c] = v;
  720.                         } while (c < n);
  721. #if 1   /* XXX another disgusting compatibility hack */
  722.                         /*
  723.                          * Alas, the V7 Unix scanf also treats formats
  724.                          * such as [a-c-e] as `the letters a through e'.
  725.                          * This too is permitted by the standard....
  726.                          */
  727.                         goto doswitch;
  728. #else
  729.                         c = *fmt++;
  730.                         if (c == 0)
  731.                                 return (fmt - 1);
  732.                         if (c == ']')
  733.                                 return (fmt);
  734. #endif
  735.                         break;
  736.  
  737.                 case ']':               /* end of scanset */
  738.                         return (fmt);
  739.  
  740.                 default:                /* just another character */
  741.                         c = n;
  742.                         break;
  743.                 }
  744.         }
  745.         /* NOTREACHED */
  746. }
  747.  
  748. int streambuf::scan(char const *format ...)
  749. {
  750.     va_list ap;
  751.     va_start(ap, format);
  752.     int count = vscan(format, ap);
  753.     va_end(ap);
  754.     return count;
  755. }
  756.